home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr05 / xnot12a.zip / ECHO.C < prev    next >
C/C++ Source or Header  |  1993-05-25  |  17KB  |  868 lines

  1. #include "jam.h"
  2. #include "stdlib.h"
  3.  
  4. /*
  5.  *        Echo line reading and writing.
  6.  *
  7.  * Common routines for reading
  8.  * and writing characters in the echo line area
  9.  * of the display screen. Used by the entire
  10.  * known universe.
  11.  */
  12. #include "def.h"
  13. #include "key.h"
  14. #include "macro.h"
  15. #include "kbd.h"
  16.  
  17. #define EchoColor /* CHIGH */ CTEXT /* for normal colored prompt stuff */
  18.  
  19. static void rn_(altmessage,(char  *s));
  20. static int rn_(getxtra, (LIST *lp1, LIST *lp2, int cpos, int wflag));
  21. static int rn_(veread, (char *fp, char *buf, int nbuf, int flag, va_list *ap));
  22. static VOID rn_(eformat, (char *fp, va_list *ap));
  23. static VOID rn_(eputi, (int i, int r));
  24. static VOID rn_(eputl, (long l, int r));
  25. static VOID rn_(eputs, (char *s));
  26. static VOID rn_(eputc, (char c));
  27. static int rn_(complt, (int flags, char c, char *buf, int cpos, int size));
  28.  
  29. int    epresf    = FALSE;        /* Stuff in echo line flag.    */
  30. BOOL    eprompting = FALSE;
  31.  
  32. /* JAM - more strings localized to prevent duplicates
  33. */
  34. BOOL ealtmsg = FALSE;
  35. static char *amb = " [Ambiguous]";
  36. static char *nomatch =  " [No match]";
  37.  
  38. static char preload[NFILEN] = {0};   /* preloaded a prompt (JAM ) */
  39. static char altmsg[2*NFILEN] = {0};  /* for interruptable prompt (JAM) */
  40. static char refreshmsg[2*NFILEN] = {0};
  41. static int refreshoffset = 0;
  42. static BOOL collectPrompt = FALSE;
  43. static int altoffset = 0; 
  44.  
  45. /*
  46.  * Erase the echo line.
  47.  */
  48. VOID eerase() 
  49. {
  50.  if (ealtmsg)
  51.    {
  52.      altmsg[0] = '\0';
  53.      altoffset = 0;
  54.    }
  55.  else
  56.    {
  57.      ttcolor(EchoColor);
  58.      ttmove(nrow-1, 0);
  59.      tteeol();
  60.      ttflush(FALSE);
  61.    }
  62.  epresf = FALSE;
  63. }
  64.  
  65. /*
  66.  * Ask "yes" or "no" question.
  67.  * Return ABORT if the user answers the question
  68.  * with the abort ("^G") character. Return FALSE
  69.  * for "no" and TRUE for "yes". No formatting
  70.  * services are available. No newline required.
  71.  */
  72. eyorn(sp) 
  73. char *sp; {
  74.     register int    s;
  75.     int result;
  76.  
  77.     if(inmacro) 
  78.       return TRUE;
  79.  
  80.         eprompting = TRUE;
  81.     ewprintf("%s? (y or n) ", sp);
  82.     for (;;) {
  83.         s = getkey(FALSE);
  84.         if (s == 'y' || s == 'Y') 
  85.           {
  86.                result = TRUE;
  87.            break;
  88.           }
  89.         if (s == 'n' || s == 'N')
  90.           {
  91.                result = FALSE;
  92.            break;
  93.           }
  94.         if (s == CCHR('G')) 
  95.           {
  96.                result = ctrlg(FFRAND, 1);
  97.            break;
  98.           }
  99.         if (!handleKchar(s))
  100.           {
  101.             result = ABORT;
  102.             break;
  103.           }
  104.  
  105.                 ttbeep();
  106.         ewprintf("Please answer y or n.  %s? (y or n) ", sp);
  107.     }
  108.  
  109.    eprompting = FALSE;
  110.    return(result);
  111. }
  112.  
  113. /*
  114.  * Like eyorn, but for more important question. User must type either all of
  115.  * "yes" or "no", and the trainling newline.
  116.  */
  117. eyesno(sp) 
  118. char *sp; 
  119. {
  120.     register int    s;
  121.     char        buf[64];
  122.  
  123.     if(inmacro) 
  124.       return TRUE;
  125.  
  126.         eprompting = TRUE;
  127.     s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
  128.     for (;;) {
  129.         if (s == ABORT) 
  130.            break;
  131.  
  132.         if (s != FALSE) {
  133.             if (macrodef) {
  134.                 LINE *lp = maclcur;
  135.  
  136.                 maclcur = lp->l_bp;
  137.                 maclcur->l_fp = lp->l_fp;
  138.                 free((char *)lp);
  139.             }
  140.  
  141.             if ((buf[0] == 'y' || buf[0] == 'Y')
  142.                 &&    (buf[1] == 'e' || buf[1] == 'E')
  143.                 &&    (buf[2] == 's' || buf[2] == 'S')
  144.                 &&    (buf[3] == '\0')) 
  145.               {
  146.               s = TRUE;
  147.               break;
  148.               }
  149.             if ((buf[0] == 'n' || buf[0] == 'N')
  150.                 &&    (buf[1] == 'o' || buf[0] == 'O')
  151.                 &&    (buf[2] == '\0'))
  152.               {
  153.               s = FALSE;
  154.               break;
  155.               }
  156.         }
  157.         if (!handleKchar(s))
  158.           {
  159.             s = ABORT;
  160.             break;
  161.           }
  162.  
  163.                 ttbeep();
  164.         s = ereply("Please answer yes or no.  %s? (yes or no) ",
  165.                buf, sizeof(buf), sp);
  166.     }
  167.    eprompting = FALSE;
  168.    return(s);
  169. }
  170. /*
  171.  * Write out a prompt, and read back a
  172.  * reply. The prompt is now written out with full "ewprintf"
  173.  * formatting, although the arguments are in a rather strange
  174.  * place. This is always a new message, there is no auto
  175.  * completion, and the return is echoed as such.
  176.  */
  177. int ereply(va_alist)
  178. va_dcl
  179. {
  180.     va_list pvar;
  181.     register char *fp, *buf;
  182.     register int nbuf;
  183.     register int i;
  184.  
  185.     va_start(pvar);
  186.     fp = va_arg(pvar, char *);
  187.     buf = va_arg(pvar, char *);
  188.     nbuf = va_arg(pvar, int);
  189.     i = veread(fp, buf, nbuf, EFNEW|EFCR, &pvar);
  190.     va_end(pvar);
  191.     return i;
  192. }
  193.  
  194. /*
  195.  * This is the general "read input from the
  196.  * echo line" routine. The basic idea is that the prompt
  197.  * string "prompt" is written to the echo line, and a one
  198.  * line reply is read back into the supplied "buf" (with
  199.  * maximum length "len"). The "flag" contains EFNEW (a
  200.  * new prompt), an EFFUNC (autocomplete), or EFCR (echo
  201.  * the carriage return as CR).
  202.  */
  203. /* VARARGS 0 */
  204. int eread(va_alist)
  205. va_dcl
  206. {
  207.     va_list pvar;
  208.     char *fp, *buf;
  209.     int nbuf, flag, i;
  210.  
  211.     va_start(pvar);
  212.     fp   = va_arg(pvar, char *);
  213.     buf  = va_arg(pvar, char *);
  214.     nbuf = va_arg(pvar, int);
  215.     flag = va_arg(pvar, int);
  216.     i = veread(fp, buf, nbuf, flag, &pvar);
  217.     va_end(pvar);
  218.     return i;
  219. }
  220.  
  221. static int veread(fp, buf, nbuf, flag, ap) 
  222. char *fp; 
  223. char *buf; 
  224. int nbuf, flag;
  225. va_list *ap; 
  226. {
  227.     register int    cpos;
  228.     register int    i;
  229.     register int    c;
  230.         int refreshlength;
  231.         BOOL wasvis = IsCaretVis();
  232.  
  233.         SetCaretVis(FALSE);
  234.         
  235.     if(inmacro) {
  236.         bcopy(maclcur->l_text, buf, (size_t)maclcur->l_used);
  237.         buf[maclcur->l_used] = '\0';
  238.         maclcur = maclcur->l_fp;
  239.         return TRUE;
  240.     }
  241.  
  242.        eprompting = TRUE;
  243.     cpos = 0;
  244.     if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
  245.         ttcolor(EchoColor);
  246.         ttmove(nrow-1, 0);
  247.         epresf = TRUE;
  248.     } else
  249.         eputc(' ');
  250.  
  251.         /* eformat will prime refreshmsg buffer
  252.         */
  253.     eformat(fp, ap);
  254.         refreshlength = strlen(refreshmsg);
  255.  
  256.        /* dump pre-loaded partial response
  257.        */
  258.     AddString(preload);
  259.     preload[0] = '\0';
  260.  
  261.     tteeol();
  262.     ttflush(FALSE);
  263.     for (;;) {
  264.                 if (wasvis)
  265.                   SetCaretVis(TRUE);
  266.         c = getkey(FALSE);
  267.                 SetCaretVis(FALSE);
  268.  
  269.         if ((flag & EFFILE) && ((c == (int)' ') 
  270.                     || (c == (int)(CCHR('I')))))
  271.           {
  272.             char dbuf[NFILEN];
  273.             register int i;
  274.  
  275.             for (i = 0; i < cpos; i++)
  276.                dbuf[i] = buf[i];
  277.             dbuf[i] = '\0';
  278.             ExtendedFunction(function_name(diredfiles_));
  279.             AddString(dbuf);
  280.             AddKchar(' ');
  281.                 continue;
  282.               }
  283.  
  284.           
  285.         if ((flag&EFAUTO) != 0 && (c == (int)' ' || 
  286.                     c == (int)CCHR('I'))) 
  287.                   {
  288.             cpos += complt(flag, (char)c, buf, cpos, nbuf);
  289.             continue;
  290.           }
  291.  
  292.         c = handleKchar(c);
  293.         if (!c)
  294.           c = CCHR('G');
  295.  
  296.         switch (c) {
  297.                     case CCHR('Z'):        
  298.                         ttcolor(EchoColor);
  299.                         ttmove(nrow-1, 0);
  300.                         eerase();
  301.                         eputs(refreshmsg);
  302.                         break;            /* refresh? ignore it*/
  303.  
  304.             case CCHR('J'):
  305.             c = CCHR('M');        /* and continue        */
  306.             case CCHR('M'):        /* Return, done.    */
  307.             if ((flag&EFFUNC) != 0) {
  308.               if ((i = complt(flag, (char)c, buf, cpos, nbuf)) == 0)
  309.                 continue;
  310.               if (i > 0) 
  311.                 cpos += i;
  312.             }
  313.             buf[cpos] = '\0';
  314.             if ((flag&EFCR) != 0) {
  315.                 ttputc(CCHR('M'));
  316.                 ttflush(FALSE);
  317.             }
  318.             if(macrodef) {
  319.                 LINE *lp;
  320.  
  321.                 if((lp = lalloc(cpos)) == NULL) 
  322.                               return FALSE;
  323.                 lp->l_fp = maclcur->l_fp;
  324.                 maclcur->l_fp = lp;
  325.                 lp->l_bp = maclcur;
  326.                 maclcur = lp;
  327.                 bcopy(buf, lp->l_text, (size_t)cpos);
  328.             }
  329.             goto done;
  330.  
  331.             case CCHR('G'):        /* Bell, abort.        */
  332.             eputc(CCHR('G'));
  333.             (VOID) ctrlg(FFRAND, 0);
  334.             ttflush(FALSE);
  335.                eprompting = FALSE;
  336.             return ABORT;
  337.  
  338.                     case KDELETE:
  339.             case CCHR('H'):
  340.             case CCHR('?'):        /* Rubout, erase.    */
  341.             if (cpos != 0) {
  342.                 ttputc('\b');
  343.                 ttputc(' ');
  344.                 ttputc('\b');
  345.                 --ttcol;
  346.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  347.                     ttputc('\b');
  348.                     ttputc(' ');
  349.                     ttputc('\b');
  350.                     --ttcol;
  351.                 }
  352.                 ttflush(FALSE);
  353.             }
  354.             break;
  355.  
  356.             case CCHR('X'):        /* C-X            */
  357.             case CCHR('U'):        /* C-U, kill line.    */
  358.             while (cpos != 0) {
  359.                 ttputc('\b');
  360.                 ttputc(' ');
  361.                 ttputc('\b');
  362.                 --ttcol;
  363.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  364.                     ttputc('\b');
  365.                     ttputc(' ');
  366.                     ttputc('\b');
  367.                     --ttcol;
  368.                 }
  369.             }
  370.             ttflush(FALSE);
  371.             break;
  372.  
  373.             case CCHR('W'):        /* C-W, kill to beginning of */
  374.                         /* previous word    */
  375.             /* back up to first word character or beginning */
  376.             while ((cpos > 0) && !ISWORD(buf[cpos - 1])) {
  377.                 ttputc('\b');
  378.                 ttputc(' ');
  379.                 ttputc('\b');
  380.                 --ttcol;
  381.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  382.                     ttputc('\b');
  383.                     ttputc(' ');
  384.                     ttputc('\b');
  385.                     --ttcol;
  386.                 }
  387.             }
  388.             while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
  389.                 ttputc('\b');
  390.                 ttputc(' ');
  391.                 ttputc('\b');
  392.                 --ttcol;
  393.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  394.                     ttputc('\b');
  395.                     ttputc(' ');
  396.                     ttputc('\b');
  397.                     --ttcol;
  398.                 }
  399.             }
  400.             ttflush(FALSE);
  401.             break;
  402.  
  403.             case CCHR('\\'):
  404.             case CCHR('Q'):        /* C-Q, quote next    */
  405.             c = getkey(FALSE);    /* and continue        */
  406.             default:            /* All the rest.    */
  407.             if (cpos < nbuf-1) {
  408.                 buf[cpos++] = (char) c;
  409.                 eputc((char) c);
  410.                 ttflush(FALSE);
  411.             }
  412.         }
  413.           memcpy(&refreshmsg[refreshlength], buf, cpos);
  414.           refreshmsg[refreshlength + cpos] = '\0';
  415.     }
  416. done:
  417.     eprompting = FALSE;
  418.     return buf[0] != '\0';
  419. }
  420.  
  421. /*
  422.  * do completion on a list of objects.
  423.  */
  424. static int complt(flags, c, buf, cpos, nbuf)
  425. int flags;
  426. char c;
  427. register char *buf;
  428. register int cpos;
  429. int nbuf;
  430. {
  431.     register LIST    *lh, *lh2;
  432.     int        i, nxtra;
  433.     int        nhits, bxtra;
  434.     int        wflag = FALSE;
  435.     int        msglen, nshown;
  436.     char        *msg;
  437. #ifdef WINDOWED
  438.         int cursoron = IsCaretVis();
  439. #endif
  440.  
  441.     if ((flags&EFFUNC) != 0) {
  442.         buf[cpos] = '\0';
  443.         i = complete_function(buf, c);
  444.         if(i>0) {
  445.         eputs(&buf[cpos]);
  446.         ttflush(FALSE);
  447.         return i;
  448.         }
  449.         switch(i) {
  450.         case -3:
  451.             msg = amb; /* ambiguous */
  452.             break;
  453.         case -2:
  454.             i=0;
  455.             msg = nomatch;
  456.             break;
  457.         case -1:
  458.         case 0:
  459.             return i;
  460.         default:
  461.             msg = " [Internal error]";
  462.             break;
  463.         }
  464.     } else {
  465.         if ((flags&EFBUF) != 0) 
  466.         lh = &(bheadp->b_list);
  467.         else 
  468.         panic("broken complt call: flags");
  469.  
  470.         if (c == ' ') 
  471.         wflag = TRUE;
  472.         else if (c != '\t' && c != CCHR('M')) 
  473.         panic("broken complt call: c");
  474.  
  475.         nhits = 0;
  476.         nxtra = HUGEN;
  477.  
  478.         while (lh != NULL) {
  479.         for (i=0; i<cpos; ++i) {
  480.             if (buf[i] != lh->l_name[i])
  481.                 break;
  482.         }
  483.         if (i == cpos) {
  484.             if (nhits == 0)
  485.                 lh2 = lh;
  486.             ++nhits;
  487.             if (lh->l_name[i] == '\0') nxtra = -1;
  488.             else {
  489.                 bxtra = getxtra(lh, lh2, cpos, wflag);
  490.                 if (bxtra < nxtra) nxtra = bxtra;
  491.                 lh2 = lh;
  492.             }
  493.         }
  494.         lh = lh->l_next;
  495.         }
  496.         if (nhits == 0)
  497.         msg = nomatch;
  498.         else if (nhits > 1 && nxtra == 0)
  499.         msg = amb;
  500.         else {        /* Got a match, do it to it */
  501.         /*
  502.          * Being lazy - ought to check length, but all things
  503.          * autocompleted have known types/lengths.
  504.          */
  505.         if (nxtra < 0 && nhits > 1 && c == ' ') 
  506.                   nxtra = 1;
  507.         for (i = 0; i < nxtra; ++i) 
  508.                   {
  509.                     if (cpos >= nbuf)
  510.                       {
  511. #ifdef WINDOWED
  512.                         WindowMessage("Echo line overflow!", FALSE);
  513. #else
  514. # ifdef SomeUnix
  515.                         printf("Echo line overflow!\n");  /* gross */
  516. # endif
  517.                         ewprintf("Echo line overflow!");  /* gross */
  518. #endif
  519.                         cpos--;
  520.                         buf[cpos] = '\0';
  521.                         break;
  522.                       }
  523.             buf[cpos] = lh2->l_name[cpos];
  524.             eputc(buf[cpos++]);
  525.           }
  526.         ttflush(FALSE);
  527.         if (nxtra < 0 && c != CCHR('M')) 
  528.                   return 0;
  529.         return nxtra;
  530.         }
  531.     }
  532.     /* Set up backspaces, etc., being mindful of echo line limit 
  533.         */
  534.     msglen = strlen(msg);
  535.     nshown = (ttcol + msglen + 2 > ncol) ?
  536.             ncol - ttcol - 2 : msglen;
  537. #ifdef WINDOWED
  538.         SetCaretVis(FALSE);
  539.         ttflush(TRUE);
  540. #endif
  541.     eputs(msg);
  542.         ttflush(TRUE);
  543.     sleep(1);
  544.     ttcol -= (i = nshown);        /* update ttcol!        */
  545.     while (i--)            /* move back before msg        */
  546.         ttputc('\b');
  547.     ttflush(FALSE);            /* display to user        */
  548.     i = nshown;
  549.     while (i--)            /* blank out    on next flush    */
  550.         eputc(' ');
  551.     ttcol -= (i = nshown);        /* update ttcol on BS's        */
  552.     while (i--)
  553.         ttputc('\b');        /* update ttcol again!        */
  554. #ifdef WINDOWED
  555.         SetCaretVis(cursoron);
  556.         ttflush(TRUE);
  557. #endif
  558.     return 0;
  559. }
  560.  
  561. /*
  562.  * The "lp1" and "lp2" point to list structures. The
  563.  * "cpos" is a horizontal position in the name.
  564.  * Return the longest block of characters that can be
  565.  * autocompleted at this point. Sometimes the two
  566.  * symbols are the same, but this is normal.
  567.   */
  568. static int getxtra(lp1, lp2, cpos, wflag) 
  569. register LIST *lp1, *lp2; 
  570. int cpos;
  571. register int wflag; 
  572. {
  573.     register int    i;
  574.  
  575.     i = cpos;
  576.     for (;;) {
  577.         if (lp1->l_name[i] != lp2->l_name[i]) break;
  578.         if (lp1->l_name[i] == '\0') break;
  579.         ++i;
  580.         if (wflag && !ISWORD(lp1->l_name[i-1])) break;
  581.     }
  582.     return (i - cpos);
  583. }
  584.  
  585. /*
  586.  * Special "printf" for the echo line.
  587.  * Each call to "ewprintf" starts a new line in the
  588.  * echo area, and ends with an erase to end of the
  589.  * echo line. The formatting is done by a call
  590.  * to the standard formatting routine.
  591.  */
  592. /*VARARGS 0 */
  593. VOID ewprintf(va_alist)
  594. va_dcl
  595. {
  596.     va_list pvar;
  597.     register char *fp;
  598.  
  599.     if (inmacro) 
  600.           return;
  601.  
  602.     va_start(pvar);
  603.     fp = va_arg(pvar, char *);
  604.     if (!ealtmsg)
  605.       {
  606.       ttcolor(EchoColor);
  607.       ttmove(nrow-1, 0);
  608.       }
  609.     eformat(fp, &pvar);
  610.     va_end(pvar);
  611.  
  612.     if (ealtmsg)
  613.       {
  614.       altmessage(altmsg);
  615.       altoffset = 0;
  616.       }
  617.     else
  618.       {
  619.       tteeol();
  620.       ttflush(FALSE);
  621.       }
  622.     epresf = TRUE;
  623. }
  624.  
  625. /*
  626.  * Printf style formatting. This is
  627.  * called by both "ewprintf" and "ereply" to provide
  628.  * formatting services to their clients. The move to the
  629.  * start of the echo line, and the erase to the end of
  630.  * the echo line, is done by the caller.
  631.  * Note: %c works, and prints the "name" of the character.
  632.  * %k prints the name of a key (and takes no arguments).
  633.  */
  634. static VOID eformat(fp, ap)
  635. register char *fp;
  636. register va_list *ap;
  637. {
  638.     register int c;
  639.     char    kname[NKNAME];
  640.     char    *cp;
  641.  
  642.         refreshoffset = 0;
  643.         refreshmsg[0] = '\0';
  644.         collectPrompt = TRUE;
  645.  
  646.     while ((c = *fp++) != '\0') {
  647.         if (c != (char)'%')
  648.             eputc((char)c);
  649.         else {
  650.             c = *fp++;
  651.             switch (c) {
  652.             case 'c':
  653.                 (VOID) mykeyname(kname, va_arg(*ap, int));
  654.                 eputs(kname);
  655.                 break;
  656.  
  657.             case 'k':
  658.                 cp = kname;
  659.                 for(c=0; c < key.k_count; c++) {
  660.                     cp = mykeyname(cp, key.k_chars[c]);
  661.                     *cp++ = ' ';
  662.                 }
  663.                 *--cp = '\0';
  664.                 eputs(kname);
  665.                 break;
  666.  
  667.             case 'd':
  668.                 eputi(va_arg(*ap, int), 10);
  669.                 break;
  670.  
  671.             case 'o':
  672.                 eputi(va_arg(*ap, int), 8);
  673.                 break;
  674.  
  675.             case 's':
  676.                 eputs(va_arg(*ap, char *));
  677.                 break;
  678.  
  679.             case 'l':/* explicit longword */
  680.                 c = *fp++;
  681.                 switch(c) {
  682.                 case 'd':
  683.                     eputl((long)va_arg(*ap, long), 10);
  684.                     break;
  685.                 default:
  686.                     eputc((char)c);
  687.                     break;
  688.                 }
  689.                 break;
  690.  
  691.             default:
  692.                 eputc((char)c);
  693.             }
  694.         }
  695.     }
  696.     collectPrompt = FALSE;
  697. }
  698.  
  699. /*
  700.  * Put integer, in radix "r".
  701.  */
  702. static VOID eputi(i, r)
  703. register int i;
  704. register int r;
  705. {
  706.     register int    q;
  707.  
  708.     if(i<0) {
  709.         eputc('-');
  710.         i = -i;
  711.     }
  712.     if ((q=i/r) != 0)
  713.         eputi(q, r);
  714.     eputc((char)(i%r+'0'));
  715. }
  716.  
  717. /*
  718.  * Put long, in radix "r".
  719.  */
  720. static VOID eputl(l, r)
  721. register long l;
  722. register int  r;
  723. {
  724.     register long    q;
  725.  
  726.     if(l < 0) {
  727.         eputc('-');
  728.         l = -l;
  729.     }
  730.     if ((q=l/r) != 0)
  731.         eputl(q, r);
  732.     eputc((char)((l%r)+'0'));
  733. }
  734.  
  735. /*
  736.  * Put string.
  737.  */
  738. static VOID eputs(s)
  739. register char *s;
  740. {
  741.   register char    c;
  742.  
  743.   while ((c = *s++) != '\0')
  744.     eputc(c);
  745.   ttflush(FALSE);
  746. }
  747.  
  748. /*
  749.  * Put character. Watch for
  750.  * control characters, and for the line
  751.  * getting too long.
  752.  */
  753. static VOID eputc(c)
  754. register char c;
  755. {
  756.   if ((ttcol+2 < ncol) || ealtmsg) 
  757.     {
  758.     if (ISCTRL(c)) 
  759.        {
  760.     eputc('^');
  761.     c = (char)CCHR(c);
  762.     }
  763.     if (ealtmsg)
  764.     {
  765.     altmsg[altoffset++] = c;
  766.     altmsg[altoffset] = 0;
  767.     }
  768.     else
  769.         {
  770.     ttputc(c);
  771.         ++ttcol;
  772.         if (collectPrompt)
  773.           {
  774.         refreshmsg[refreshoffset++] = c;
  775.             refreshmsg[refreshoffset] = 0;
  776.           }
  777.         }
  778.     }
  779. }
  780.  
  781. /* Alternative message dumping which will
  782.  * not mess up current status (for code running during timer
  783.  * callback, for example)
  784.  */
  785. static void altmessage(s)
  786. char *s;
  787. {
  788.   int curcolor;
  789.   int currow, curcol;
  790.  
  791.   if (ttfatal())
  792.     return;
  793.  
  794.   currow = ttrow;
  795.   curcol = ttcol;
  796.   curcolor = tthue;
  797.   ttcolor(EchoColor); 
  798.  
  799.   ttmove(nrow - 1, 0); 
  800.   tteeol();
  801.   ttputline(s);
  802.  
  803.   ttcolor(curcolor);
  804.   ttmove(currow, curcol);
  805.   ttflush(FALSE);
  806. }
  807.  
  808. /* Deal with unexpected chars during echo-line stuff.
  809. * (ughly!)
  810. * Attempts to collect events from 'interrupting' commands
  811. * to be re-entered into input stream later (main.c)
  812. */
  813. BOOL handleKchar(c)
  814. int c;
  815. {
  816.   int s = c;
  817.   BOOL metakey = FALSE;
  818.  
  819.   if (s == CCHR('['))
  820.     {
  821.     s = getkey(FALSE);          /* grab the key and throw it away */
  822.     s |= METABIT;
  823.     metakey = TRUE;
  824.     }
  825.  
  826.   switch (c)
  827.     {
  828.     case KEXTEND:                /* silent_extended command */
  829.       PutbackKchar((KCHAR)c);    /* put back trigger char... */
  830.       ttflushinput(FALSE);     /* and any parameters..*/
  831.       c = 0;
  832.       break;
  833.     default:
  834.       break;
  835.     }
  836.  
  837.   if (metakey)
  838.     {
  839.       PutbackKchar((KCHAR)s);
  840.       ttflushinput(FALSE);
  841.     }
  842.  
  843.   return(c);
  844. }
  845.  
  846. /* preload prompt screen
  847. */
  848. void epreload(s)
  849. char *s;
  850.   if (preload_)
  851.     strcpy(preload, s);
  852.   else
  853.     preload[0] = '\0';
  854.   enable_preload();
  855. }
  856.  
  857. void erepair()
  858. {
  859.   if (epresf || eprompting)
  860.     {
  861.       AddKchar(CCHR('Z'));
  862.       ttflush(FALSE);
  863.     }
  864. }
  865.  
  866.